#include "Ast.h"
#include "SymbolTable.h"
#include "Unit.h"
#include "Instruction.h"
#include "IRBuilder.h"
#include <string>
#include "Type.h"

extern FILE *yyout;
int Node::counter = 0;
IRBuilder* Node::builder = nullptr;

Node::Node()
{
    seq = counter++;
}

void Node::backPatch(std::vector<Instruction*>& list, BasicBlock* bb) {
    for (auto& inst : list) {
        if (inst->isCond())
            dynamic_cast<CondBrInstruction*>(inst)->setTrueBranch(bb);
        else if (inst->isUncond())
            dynamic_cast<UncondBrInstruction*>(inst)->setBranch(bb);
    }
}


std::vector<Instruction*> Node::merge(std::vector<Instruction*> &list1, std::vector<Instruction*> &list2)
{
    std::vector<Instruction*> res(list1);
    res.insert(res.end(), list2.begin(), list2.end());
    return res;
}

void Ast::genCode(Unit *unit)
{
    //std::cout  << "start" << std::endl;
    IRBuilder *builder = new IRBuilder(unit);
    Node::setIRBuilder(builder);
    fprintf(yyout, "declare i32 @getint()\ndeclare void @putint(i32)\ndeclare i32 @getch()\ndeclare void @putch(i32)\n");
    root->genCode();
    //std::cout  << "end" << std::endl;
}


//gencode

void FunctionDef::genCode()
{
    //std::cout  << "start0" << std::endl;
    Unit *unit = builder->getUnit();
    Function *func = new Function(unit, se);
    BasicBlock *entry = func->getEntry();
    // set the insert point to the entry basicblock of this function.
    builder->setInsertBB(entry);
    
    if(FPs != nullptr)
    {
        FPs -> genCode();
    }

    stmt->genCode();

    /**
     * Construct control flow graph. You need do set successors and predecessors for each basic block.
     * Todo
    */
    //std::cout  << "end0" << std::endl;
    // 遍历Function中所有的BasicBlock，在各个BasicBlock之间建立控制流关系
    for (auto block = func->begin(); block != func->end(); block++) {
        // 清除ret之后的全部指令
        
        Instruction* i = (*block)->begin();
        //获取该块的最后一条指令
        Instruction* last = (*block)->rbegin();
        while (i != last) {
            if (i->isCond() || i->isUncond()) {
                (*block)->remove(i);
            }
            i = i->getNext();
        }
        // 对于有条件的跳转指令，需要对其true分支和false分支都设置控制流关系
        if (last->isCond()) {
            BasicBlock *truebranch, *falsebranch;
            truebranch =dynamic_cast<CondBrInstruction*>(last)->getTrueBranch();
            falsebranch =dynamic_cast<CondBrInstruction*>(last)->getFalseBranch();
            (*block)->addSucc(truebranch);
            (*block)->addSucc(falsebranch);
            truebranch->addPred(*block);
            falsebranch->addPred(*block);
        } 
        
        if (last->isUncond())  //无条件跳转指令可获取跳转的目标块
        {
            BasicBlock* dst =dynamic_cast<UncondBrInstruction*>(last)->getBranch();
            (*block)->addSucc(dst);
            dst->addPred(*block);
            if (dst->empty()) {
                if (((FunctionType*)(se->getType()))->getRetType() ==TypeSystem::intType)
                    new RetInstruction(new Operand(new ConstantSymbolEntry(TypeSystem::intType, 0)),dst);
                else if (((FunctionType*)(se->getType()))->getRetType() ==TypeSystem::voidType)
                    new RetInstruction(nullptr, dst);
            }
        }
        //最后一条语句不是返回以及跳转
        else if (!last->isRet()) {
            if (((FunctionType*)(se->getType()))->getRetType() ==
                TypeSystem::voidType) {
                new RetInstruction(nullptr, *block);
            }
        }
    }
}

void BinaryExpr::genCode()
{
    BasicBlock *bb = builder->getInsertBB();
    Function *func = bb->getParent();
    if (op == AND)
    {
        BasicBlock* trueBB = new BasicBlock(func);  // if the result of lhs is true, jump to the trueBB.
        expr1->genCode();
        backPatch(expr1->trueList(), trueBB);
        builder->setInsertBB(trueBB);  // set the insert point to the trueBB so that intructions generated by expr2 will be inserted into it.
        expr2->genCode();
        true_list = expr2->trueList();
        false_list = merge(expr1->falseList(), expr2->falseList());
    }
    else if(op == OR)
    {
        // Todo
        BasicBlock* trueBB = new BasicBlock(func);
        expr1->genCode();
        backPatch(expr1->falseList(), trueBB);
        builder->setInsertBB(trueBB);
        expr2->genCode();
        true_list = merge(expr1->trueList(), expr2->trueList());
        false_list = expr2->falseList();
    }
    else if(op >= LESS && op <= MORE)
    {
        // Todo
        expr1->genCode();
        expr2->genCode();
        Operand *src1 = expr1->getOperand();
        Operand *src2 = expr2->getOperand();
        int opcode;
        switch (op)
        {
        case MORE:
            opcode = CmpInstruction::G;
            break;
        case MOREEQUAL:
            opcode = CmpInstruction::GE;
            break;
        case LESS:
            opcode = CmpInstruction::L;
            break;
        case LESSEQUAL:
            opcode = CmpInstruction::LE;
            break;
        case EQUAL:
            opcode = CmpInstruction::E;
            break;
        case NOEQUAL:
            opcode = CmpInstruction::NE;
            break;
        default:
            break;
        }
        
        new CmpInstruction(opcode, dst, src1, src2, bb);

        BasicBlock *truebb, *falsebb, *tempbb;

        //
        truebb = new BasicBlock(func);
        falsebb = new BasicBlock(func);
        tempbb = new BasicBlock(func);

        true_list.push_back(new CondBrInstruction(truebb, falsebb, dst, bb));
        false_list.push_back(new UncondBrInstruction(tempbb, falsebb));

        
    }
    else if(op >= ADD && op <= SUB)
    {
        expr1->genCode();
        expr2->genCode();
        Operand *src1 = expr1->getOperand();
        Operand *src2 = expr2->getOperand();
        int opcode;
        switch (op)
        {
        case ADD:
            opcode = BinaryInstruction::ADD;
            break;
        case SUB:
            opcode = BinaryInstruction::SUB;
            break;
        case MUL:
            opcode = BinaryInstruction::MUL;
            break;
        case DIV:
            opcode = BinaryInstruction::DIV;
            break;
        case PERC:
            opcode = BinaryInstruction::MOD;
            break;
        }
        new BinaryInstruction(opcode, dst, src1, src2, bb);
    }
}

void Constant::genCode()
{
    // do nothing
}

void Id::genCode()
{
    BasicBlock *bb = builder->getInsertBB();
    Operand *addr = dynamic_cast<IdentifierSymbolEntry*>(symbolEntry)->getAddr();
    new LoadInstruction(dst, addr, bb);
}

void IfStmt::genCode()
{
    Function *func;
    BasicBlock *then_bb, *end_bb;

    func = builder->getInsertBB()->getParent();
    then_bb = new BasicBlock(func);
    end_bb = new BasicBlock(func);

    cond->genCode();//生成 cond 结点的中间代码
    backPatch(cond->trueList(), then_bb);//cond 为真时将跳转到基本块 then bb，cond 为假时将跳转到基本块 end bb
    backPatch(cond->falseList(), end_bb);

    builder->setInsertBB(then_bb);//设置插入点为基本块 then bb
    thenStmt->genCode();
    then_bb = builder->getInsertBB();//因为生成thenstmt 结点中间代码的过程中可能改变指令的插入点，因此更新
    new UncondBrInstruction(end_bb, then_bb);//生成无条件跳转指令跳转到 end bb。

    builder->setInsertBB(end_bb);//最后设置后续指令的插入点为 end bb。

}

void IfElseStmt::genCode()
{
    // Todo完成
    Function* func;
    BasicBlock *then_bb, *else_bb, *end_bb;

    func = builder->getInsertBB()->getParent();
    then_bb = new BasicBlock(func);
    else_bb = new BasicBlock(func);
    end_bb = new BasicBlock(func);

    cond->genCode();
    backPatch(cond->trueList(), then_bb);
    backPatch(cond->falseList(), else_bb);

    // 先处理then分支
    builder->setInsertBB(then_bb);
    thenStmt->genCode();
    then_bb = builder->getInsertBB();
    new UncondBrInstruction(end_bb, then_bb);

    // 再处理else分支
    builder->setInsertBB(else_bb);
    elseStmt->genCode();
    else_bb = builder->getInsertBB();
    new UncondBrInstruction(end_bb, else_bb);

    builder->setInsertBB(end_bb);
}

void CompoundStmt::genCode()//复合语句
{
    stmt -> genCode();
}

void SeqNode::genCode()
{
    stmt1 -> genCode();
    stmt2 -> genCode();
}

void DeclStmt::genCode()
{
    //std::cout  << "start8" << std::endl;
    for(auto iter = ids->Ids.rbegin(); iter != ids->Ids.rend(); iter++)
    {
        IdentifierSymbolEntry *se = dynamic_cast<IdentifierSymbolEntry *>((*iter)-> getSymPtr());
        if(se->isGlobal())
        {
            Operand *addr;
            SymbolEntry *addr_se;
            addr_se = new IdentifierSymbolEntry(*se);
            addr_se->setType(new PointerType(se->getType()));
            addr = new Operand(addr_se);
            se->setAddr(addr);
            bool temp = false;
            Operand *src;
            for(long unsigned int i = 0; i < ids -> Assigns.size(); i++)
            {
                if(ids -> Assigns[i] -> lval -> symbolEntry == se)
                {
                    ids -> Assigns[i] -> genCode();
                    src = ids -> Assigns[i] -> expr -> getOperand();
                    temp = true;
                    break; 
                }              
            }
            if(temp == false)
            {
                SymbolEntry *se = new ConstantSymbolEntry(TypeSystem::intType, 0);
                Constant* digit = new Constant(se);
                src = digit -> getOperand();
            }
            Instruction *alloca = new AllocaInstruction2(src, addr, se);
            alloca -> output();
        }
        else if(se->isLocal())
        {
            Function *func = builder->getInsertBB()->getParent();
            BasicBlock *entry = func->getEntry();
            Instruction *alloca;
            Operand *addr;
            SymbolEntry *addr_se;
            Type *type;
            type = new PointerType(se->getType());
            addr_se = new TemporarySymbolEntry(type, SymbolTable::getLabel());
            addr = new Operand(addr_se);
            alloca = new AllocaInstruction(addr, se);                   // allocate space for local id in function stack.
            entry->insertFront(alloca);                                 // allocate instructions should be inserted into the begin of the entry block.
            se->setAddr(addr);                                          // set the addr operand in symbol entry so that we can use it in subsequent code generation.
        }
    }
    for(long unsigned int i = 0; i < ids -> Assigns.size(); i++)
    {
        IdentifierSymbolEntry *se = dynamic_cast<IdentifierSymbolEntry *>(ids -> Assigns[i] -> lval -> getSymPtr());
        if(se -> isGlobal())
        { 
            continue;                   
        }
        else if(se -> isLocal())
        {
            Operand *addr = dynamic_cast<IdentifierSymbolEntry*>(ids -> Assigns[i] -> lval ->getSymPtr())->getAddr();
            se->setAddr(addr); 
            ids -> Assigns[i] -> genCode();
        }
    }
    //std::cout  << "end8" << std::endl;
}

void ReturnStmt::genCode()
{
    // Todo完成
    BasicBlock *bb = builder->getInsertBB();
    if(retValue != nullptr) {
        //操作返回值
        retValue->genCode();
        Operand* src = retValue -> getOperand();
        //打印return语句
        new RetInstruction(src, bb);
    }
    else {
        new RetInstruction(nullptr, bb);
    }
}

void AssignStmt::genCode()
{
    //std::cout  << "start10" << std::endl;
    BasicBlock *bb = builder->getInsertBB();
    expr->genCode();
    Operand *addr = dynamic_cast<IdentifierSymbolEntry*>(lval->getSymPtr())->getAddr();
    Operand *src = expr->getOperand();
    /***
     * We haven't implemented array yet, the lval can only be ID. So we just store the result of the `expr` to the addr of the id.
     * If you want to implement array, you have to caculate the address first and then store the result into it.
     */
    new StoreInstruction(addr, src, bb);
    //std::cout  << "end10" << std::endl;
}

void SignleStmt::genCode()
{
    expr -> genCode();
}

void Empty::genCode()
{
    //什么都不做
}

void FuncRParams::genCode()//函数实参
{
    //std::cout  << "start12" << std::endl;
    //std::cout  << "end12" << std::endl;
}

void FuncFParam::genCode()//函数形参
{
    //什么都不做
    BasicBlock *bb = builder->getInsertBB();
    Operand *addr = dynamic_cast<IdentifierSymbolEntry*>(symbolEntry)->getAddr();
    new LoadInstruction(dst, addr, bb);
}

void FuncFParams::genCode()//函数形参列表
{
    //std::cout  << "start15" << std::endl;
    Function *func = builder -> getInsertBB() -> getParent();
    for(long unsigned int i = 0; i < FPs.size(); i++)
    {
        // BasicBlock *bb = builder->getInsertBB();
        // Operand *addr = dynamic_cast<IdentifierSymbolEntry*>(FPs[i] -> symbolEntry)->getAddr();
        // func->insertparam(addr);
        IdentifierSymbolEntry *se = dynamic_cast<IdentifierSymbolEntry *>(FPs[i]->getSymPtr());
        //if(FPs[i]->getOperand() == nullptr) std::cout << "fun";
        Type *type1 = new PointerType(se->getType());
        Type *type2 = new IntType(32);
        SymbolEntry *addr_se = new TemporarySymbolEntry(type2, SymbolTable::getLabel());
        Operand *addr = new Operand(addr_se);

        SymbolTable :: counter++; //为了分配新的
        SymbolEntry *addr_se2 = new TemporarySymbolEntry(type1, SymbolTable::getLabel());
        Operand *addr2 = new Operand(addr_se2);


        //SymbolEntry *temp = new TemporarySymbolEntry(type, SymbolTable::getLabel());
        BasicBlock *entry = func->getEntry();
        Instruction *alloca;
        alloca = new AllocaInstruction(addr2, se);                   // allocate space for local id in function stack.
        entry->insertBack(alloca);                                   // allocate instructions should be inserted into the begin of the entry block. 
        StoreInstruction *store = new StoreInstruction(addr2, addr);
        entry -> insertBack(store);


        se->setAddr(addr2);   
        func->params.push_back(addr); 
    }
    //fprintf(yyout, "test\n");
    //std::cout  << "end15" << std::endl;
}

void FunctionCall::genCode()
{
    //std::cout  << "start19" << std::endl;
    std::vector<Operand*> params;
    //bool isnull = true;
    if(RPs != nullptr)
    for(unsigned i = 0; i < RPs -> Exprs.size(); i++)
    {
        //isnull = false;
        if(RPs -> Exprs[i] != nullptr)
        RPs -> Exprs[i] -> genCode();
        params.push_back(RPs -> Exprs[i] -> getOperand());
    }
    BasicBlock *entry = builder -> getInsertBB();

    Type *type2 = new IntType(32);
    SymbolTable :: counter++; //为了分配新的
    SymbolEntry *addr_se2 = new TemporarySymbolEntry(type2, SymbolTable::getLabel());
    dst = new Operand(addr_se2);
    FunctioncallInstruction *temp = new FunctioncallInstruction(dst ,symbolEntry, params);
    entry -> insertBack(temp);
    //this -> symbolEntry = addr_se2;
    //std::cout  << "end19" << std::endl;
}

void ConstIdList::genCode()
{
    //什么都不做
}

void IdList::genCode()
{
    //设么都不做
}

void WhileStmt::genCode()
{
    Function* func;
    BasicBlock *cond_bb, *while_bb, *end_bb, *bb= builder->getInsertBB();

    func = builder->getInsertBB()->getParent();
    cond_bb = new BasicBlock(func);
    while_bb = new BasicBlock(func);
    end_bb = new BasicBlock(func);

    this->cond_bb = cond_bb;
    this->end_bb = end_bb;

    // 先从当前的bb跳转到cond_bb进行条件判断
    new UncondBrInstruction(cond_bb, bb);

    // 调整插入点到cond_bb，对条件判断部分生成中间代码
    builder->setInsertBB(cond_bb);
    cond->genCode();
    backPatch(cond->trueList(), while_bb);
    backPatch(cond->falseList(), end_bb);

    // 调整插入点到stmt_bb，对循环体部分生成中间代码
    builder->setInsertBB(while_bb);
    stmt->genCode();

    // 循环体完成之后，无条件跳转到cond_bb
    while_bb = builder->getInsertBB();
    new UncondBrInstruction(cond_bb, while_bb);

    // 重新调整插入点到end_bb
    builder->setInsertBB(end_bb);
}

void ConstDeclStmt::genCode()
{
    for(long unsigned int i = 0; i < Cids -> CIds.size(); i++)
    {
        IdentifierSymbolEntry *se = dynamic_cast<IdentifierSymbolEntry *>(Cids -> CIds[i] -> getSymPtr());
        if(se->isGlobal())
        {
            Operand *addr;
            SymbolEntry *addr_se;
            addr_se = new IdentifierSymbolEntry(*se);
            addr_se->setType(new PointerType(se->getType()));
            addr = new Operand(addr_se);
            se->setAddr(addr);
            Cids -> Assigns[i] -> genCode();
            Operand *src = Cids -> Assigns[i] -> expr -> getOperand();
            Instruction *alloca = new AllocaInstruction2(src ,addr, se);
            alloca -> output();
        }
        else if(se->isLocal())
        {
            Function *func = builder->getInsertBB()->getParent();
            BasicBlock *entry = func->getEntry();
            Instruction *alloca;
            Operand *addr;
            SymbolEntry *addr_se;
            Type *type;
            type = new PointerType(se->getType());
            addr_se = new TemporarySymbolEntry(type, SymbolTable::getLabel());
            addr = new Operand(addr_se);
            alloca = new AllocaInstruction(addr, se);                   // allocate space for local id in function stack.
            entry->insertFront(alloca);                                 // allocate instructions should be inserted into the begin of the entry block.
            se->setAddr(addr);

            Cids -> Assigns[i] -> expr -> genCode();
            Operand *addr1 = dynamic_cast<IdentifierSymbolEntry*>(Cids -> Assigns[i] -> lval ->getSymPtr())->getAddr();
            se->setAddr(addr1); 
            Operand *src = Cids -> Assigns[i] -> expr -> getOperand();
            BasicBlock *ttt = builder -> getInsertBB();
            new StoreInstruction(addr1, src, ttt);                                          // set the addr operand in symbol entry so that we can use it in subsequent code generation.
        }
    }
}

void ContinueStmt::genCode()
{
    // Todo
    Function* func = builder->getInsertBB()->getParent();
    BasicBlock* bb = builder->getInsertBB();

    // 获取条件判断block
    BasicBlock* cond_bb = ((WhileStmt*)whileStmt)->get_cond_bb();
    // 在当前基本块中生成一条跳转到条件判断的语句
    new UncondBrInstruction(cond_bb, bb);
    // 声明一个新的基本块用来插入后续的指令
    BasicBlock* continue_next_bb = new BasicBlock(func);
    builder->setInsertBB(continue_next_bb);
}

void BreakStmt::genCode()
{
    //std::cout  << "start22" << std::endl;
    //std::cout  << "end22" << std::endl;
}

void ConstId::genCode()
{
    //do nothing!
}

void SignleExpr::genCode()
{
    BasicBlock *bb = builder->getInsertBB();
    if(op == EXCLAMATION)
    {
        Operand *src = expr->getOperand(); 
        SymbolEntry *se = new ConstantSymbolEntry(TypeSystem::intType, 0);
        Constant* digit = new Constant(se);
        expr->genCode();
        if(!expr -> getOperand() -> getType() -> isBool()){
            Operand* t=new Operand(new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel()));
            new CmpInstruction(CmpInstruction::EXCLAMATION, t, src, digit->getOperand(), bb);
            src=t;
        }
        new XorInstruction(dst,src,bb);
        dst -> getType() -> kind = 4;
        isCond = true;
    }
    if(op >= SUB && op <= ADD)
    {
        expr->genCode();
        Operand *src = expr->getOperand();
        if(src -> getType() -> isBool())
        {
            Operand* t =new Operand(new TemporarySymbolEntry(TypeSystem::intType,SymbolTable::getLabel()));
            new ZextInstruction(t,expr -> dst,bb); 
            expr -> dst = t;   
            src = t; 
        }
        int opcode;
        switch (op)
        {
        case ADD:
            opcode = BinaryInstruction::ADD;
            break;
        case SUB:
            opcode = BinaryInstruction::SUB;
            break;
        default:
            break;
        }
        SymbolEntry *se = new ConstantSymbolEntry(TypeSystem::intType, 0);
        Constant* digit = new Constant(se);
        new BinaryInstruction(opcode, dst, digit -> getOperand(), src, bb);
        isCond = expr -> isCond;
    }
}


//typecheck

void Ast::typeCheck()
{
    fprintf(yyout, ";TypeCheck Begin!\n");
    if(root != nullptr)
        root->typeCheck();
}

void FunctionDef::typeCheck()
{
    fprintf(yyout, ";FunctionDef %s typecheck Begin!\n", se->toStr().c_str());
    stmt->typeCheck();
    //if(stmt -> type == nullptr)
    //{
        //fprintf(stderr, "Missing Return Statement!\n");
        //exit(EXIT_FAILURE);
    //}
    //if(se -> getType() != stmt -> type)
    //{
        //fprintf(stderr, "FunctionDef %s typecheck Dismatch!\n",
                //se -> getType() -> toStr().c_str());
        //exit(EXIT_FAILURE);
    //}
    //type = se -> getType();
    // Todo
}

void BinaryExpr::typeCheck()
{ 
    // Todo
    Type *type1 = expr1 -> getSymPtr() -> getType();
    Type *type2 = expr2 -> getSymPtr() -> getType();
    if(type1 != type2){
        fprintf(stderr, "type %s and %s mismatch",
                type1 -> toStr().c_str(), type2 -> toStr().c_str());
        exit(EXIT_FAILURE);
    }
    fprintf(yyout, ";BinaryExpr TypeCheck OK!\n");
    symbolEntry -> setType(type1);
    expr1 -> typeCheck();
    expr2 -> typeCheck();
}

void Constant::typeCheck()
{
    // Todo

}

void Id::typeCheck()
{
    // Todo
}

void IfStmt::typeCheck()
{
    // Todo
    cond -> typeCheck();
    thenStmt -> typeCheck();
}

void IfElseStmt::typeCheck()
{
    // Todo
    cond -> typeCheck();
    thenStmt -> typeCheck();
    elseStmt -> typeCheck();
}

void CompoundStmt::typeCheck()
{
    // Todo
}

void SeqNode::typeCheck()
{
    // Todo
}

void DeclStmt::typeCheck()
{
    // Todo
}

void ReturnStmt::typeCheck()
{
    fprintf(yyout, ";Return Statement Type Check begin!\n");
    if(retValue != nullptr)
    {
        retValue -> typeCheck();
        type = retValue -> getOperand() -> getType();
    }
    else
    {
        type = new VoidType();
    }
}

void AssignStmt::typeCheck()
{
    // Todo
}


void SignleStmt::typeCheck()
{

}

void FuncRParams::typeCheck()
{
    
}

void Empty::typeCheck()
{
    
}

void FuncFParam::typeCheck()
{
    
}

void FuncFParams::typeCheck()
{
    
}

void ConstIdList::typeCheck()
{
    
}

void IdList::typeCheck()
{
    
}

void WhileStmt::typeCheck()
{
    
}

void FunctionCall::typeCheck()
{
    
}

void ConstDeclStmt::typeCheck()
{
    
}

void ContinueStmt::typeCheck()
{
    
}

void BreakStmt::typeCheck()
{
    
}

void ConstId::typeCheck()
{
    
}

void SignleExpr::typeCheck()
{
    Type *type = expr -> getSymPtr() -> getType();
    if(type -> isVoid()){
        fprintf(stderr, "type can't be void");
        exit(EXIT_FAILURE);
    }
    symbolEntry -> setType(type);
    expr -> typeCheck();
}


//output 

void Ast::output()
{
    fprintf(yyout, "program\n");
    if(root != nullptr)
        root->output(4);
}

void BinaryExpr::output(int level)
{
    std::string op_str;
    switch(op)
    {
        case ADD:
            op_str = "add";
            break;
        case SUB:
            op_str = "sub";
            break;
        case AND:
            op_str = "and";
            break;
        case OR:
            op_str = "or";
            break;
        case LESS:
            op_str = "less";
            break;
        case MORE:
            op_str = "more";
            break;
        case MOREEQUAL:
            op_str = "moreequal";
            break;
        case LESSEQUAL:
            op_str = "lessequal";
            break;
        case EQUAL:
            op_str = "equal";
            break;
        case NOEQUAL:
            op_str = "noequal";
            break;
        case DIV:
            op_str = "div";
            break;
        case MUL:
            op_str = "mul";
            break;
        case PERC:
            op_str = "mod";
            break;
    }
    fprintf(yyout, "%*cBinaryExpr\top: %s\n", level, ' ', op_str.c_str());
    expr1->output(level + 4);
    expr2->output(level + 4);
}

void SignleExpr::output(int level)
{
    std::string op_str;
    switch(op)
    {
        case SUB:
            op_str = "negative";
            break;
        case ADD:
            op_str = "positive";
            break;
        case EXCLAMATION:
            op_str = "anti";
            break;
    }
    fprintf(yyout, "%*cSignleExpr\top: %s\n", level, ' ', op_str.c_str());
    expr->output(level + 4);
}


void Constant::output(int level)
{
    std::string type, value;
    type = symbolEntry->getType()->toStr();
    value = symbolEntry->toStr();
    fprintf(yyout, "%*cIntegerLiteral\tvalue: %s\ttype: %s\n", level, ' ',
            value.c_str(), type.c_str());
}

void ConstId::output(int level)
{
    std::string name, type;
    int scope;
    name = symbolEntry->toStr();
    type = symbolEntry->getType()->toStr();
    scope = dynamic_cast<IdentifierSymbolEntry*>(symbolEntry)->getScope();
    fprintf(yyout, "%*cConstId\tname: %s\tscope: %d\ttype: %s\n", level, ' ',
            name.c_str(), scope, type.c_str());
}

void Id::output(int level)
{
    std::string name, type;
    int scope;
    name = symbolEntry->toStr();
    type = symbolEntry->getType()->toStr();
    scope = dynamic_cast<IdentifierSymbolEntry*>(symbolEntry)->getScope();
    fprintf(yyout, "%*cId\tname: %s\tscope: %d\ttype: %s\n", level, ' ',
            name.c_str(), scope, type.c_str());
}

void FuncFParam::output(int level)
{
    std::string name, type;
    int scope;
    name = symbolEntry -> toStr();
    type = symbolEntry -> getType() -> toStr();
    scope = dynamic_cast<IdentifierSymbolEntry*>(symbolEntry) -> getScope();
    fprintf(yyout, "%*cFuncFParam\tname:%s\tscope:%d\ttype:%s\n", level, ' ',
            name.c_str(), scope, type.c_str());
}

void CompoundStmt::output(int level)
{
    fprintf(yyout, "%*cCompoundStmt\n", level, ' ');
    stmt->output(level + 4);
}

void SeqNode::output(int level)
{
    fprintf(yyout, "%*cSequence\n", level, ' ');
    stmt1->output(level + 4);
    stmt2->output(level + 4);
}

void BreakStmt::output(int level)
{
    fprintf(yyout, "%*cBreakStmt\n", level, ' ');
}

void ContinueStmt::output(int level)
{
    fprintf(yyout, "%*cContinueStmt\n", level, ' ');
}

void DeclStmt::output(int level)
{
    fprintf(yyout, "%*cDeclStmt\n", level, ' ');
    ids->output(level + 4);
}

void ConstDeclStmt::output(int level)
{
    fprintf(yyout, "%*cConstDeclStmt\n", level, ' ');
    Cids->output(level + 4);
}

void IfStmt::output(int level)
{
    fprintf(yyout, "%*cIfStmt\n", level, ' ');
    cond->output(level + 4);
    thenStmt->output(level + 4);
}

void IfElseStmt::output(int level)
{
    fprintf(yyout, "%*cIfElseStmt\n", level, ' ');
    cond->output(level + 4);
    thenStmt->output(level + 4);
    elseStmt->output(level + 4);
}

void ReturnStmt::output(int level)
{
    fprintf(yyout, "%*cReturnStmt\n", level, ' ');
    retValue->output(level + 4);
}

void AssignStmt::output(int level)
{
    fprintf(yyout, "%*cAssignStmt\n", level, ' ');
    lval->output(level + 4);
    expr->output(level + 4);
}

void FunctionDef::output(int level)
{
    std::string name, type;
    name = se->toStr();
    type = se->getType()->toStr();
    fprintf(yyout, "%*cFunctionDefine function name: %s, type: %s\n", level, ' ', 
            name.c_str(), type.c_str());
    if(FPs != nullptr){
        FPs -> output(level + 4);
    }
    stmt->output(level + 4);
}

void FunctionCall::output(int level)
{
    std::string name, type;
    name = symbolEntry->toStr();
    type = symbolEntry->getType()->toStr();
    fprintf(yyout, "%*cFuncCall\tname: %s\ttype: %s\n", level, ' ',
            name.c_str(), type.c_str());
    if(RPs != nullptr)
    {
        RPs -> output(level + 4);
    }
}

void WhileStmt::output(int level)
{
    fprintf(yyout, "%*cWhileStmt\n", level, ' ');
    cond->output(level + 4);
    stmt->output(level + 4);
}

void IdList::output(int level)
{
    fprintf(yyout, "%*cIdList\n", level, ' ');
    for(long unsigned int i = 0; i < Ids.size(); i++)
    {
        Ids[i] -> output(level + 4);
    }
    for(long unsigned int i = 0; i < Assigns.size(); i++)
    {
        Assigns[i] -> output(level + 4);
    }
}
void ConstIdList::output(int level)
{
    fprintf(yyout, "%*cConstIdList\n", level, ' ');
    for(long unsigned int i = 0; i < CIds.size(); i++)
    {
        CIds[i] -> output(level + 4);
        Assigns[i] -> output(level + 4);
    }
}

void FuncFParams::output(int level)
{
    fprintf(yyout, "%*cFuncFParams\n", level, ' ');
    for(long unsigned int i = 0; i < FPs.size(); i++)
    {
        FPs[i] -> output(level + 4);
    }
    for(long unsigned int i = 0; i < Assigns.size(); i++)
    {
        Assigns[i] -> output(level + 4);
    }
}

void FuncRParams::output(int level)
{
    fprintf(yyout, "%*cFuncRParams\n", level, ' ');
    for(long unsigned int i = 0; i < Exprs.size(); i++)
    {
        Exprs[i] -> output(level + 4);
    }
}

void Empty::output(int level)
{
    fprintf(yyout, "%*cEmpty Statement\n", level, ' ');
}

void SignleStmt::output(int level)
{
    fprintf(yyout, "%*cSignle Statement\n", level, ' ');
    expr -> output(level + 4);
}